package com.wangjiang.mario.admin.system.domain.components;

import com.wangjiang.mario.admin.common.util.CommonUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public class CacheComponent {


    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
        redisTemplate.setConnectionFactory(factory);

        //key序列化方式;（不然会出现乱码;）,但是如果方法上有Long等非String类型的话，会报类型转换错误；
        //所以在没有自己定义key生成策略的时候，以下这个代码建议不要这么写，可以不配置或者自己实现ObjectRedisSerializer
        //或者JdkSerializationRedisSerializer序列化方式;
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);
        redisTemplate.setValueSerializer(redisSerializer);
        redisTemplate.setHashValueSerializer(redisSerializer);

        return redisTemplate;
    }

    @Resource(name = "redisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

//    @Resource(name = "stringRedisTemplate")
//    private StringRedisTemplate stringRedisTemplate;

    /**
     * 添加数据对象到缓存
     *
     * @param key      主KEY
     * @param childKey 子KEY
     * @param object   数据对象
     * @param timeout  缓存时间：秒
     */
    public void put(String key, String childKey, Object object, long timeout) {
        putForExpire(key, childKey, object, timeout);
    }

    /**
     * 从缓存中获取数据对象
     *
     * @param key      主KEY
     * @param childKey 子KEY
     * @return 数据对象
     */
    public Object get(String key, String childKey) {
        return getForExpire(key, childKey);
    }

    /**
     * 从缓存中移除数据对象
     *
     * @param key      主KEY
     * @param childKey 子KEY
     */
    public void remove(String key, String childKey) {
        removeForExpire(key, childKey);
    }

    /**
     * 添加数据对象到缓存
     *
     * @param key      主KEY
     * @param childKey 子KEY
     * @param value    数据对象
     * @param timeout  缓存时间：秒
     */
    public void putForExpire(String key, String childKey, Object value, long timeout) {
        BoundValueOperations<String, Object> boundValueOperations = redisTemplate.boundValueOps(getFinallyKey(key, childKey));
        boundValueOperations.set(value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 取通过 putForExpire方法添加的缓存值
     * @param key
     * @param childKey
     */
    public Object getForExpire(String key, String childKey) {
        return redisTemplate.boundValueOps(getFinallyKey(key, childKey)).get();
    }

    /**
     * 获取某个key的剩余过期时间
     */
    public Long getKeyLeftSeconds(String key, String childKey) {
        return redisTemplate.getExpire(key+childKey);
    }

    /**
     * 删除通过 putForExpire方法添加的缓存值
     *
     * @param key
     * @param childKey
     */
    public void removeForExpire(String key, String childKey) {
        redisTemplate.delete(getFinallyKey(key, childKey));
    }

    /**
     * 删除所有指定前缀的key
     * @param prex
     * @return
     */
    public void deleteByPrex(String prex) {
        System.out.println("======prex:========");
        System.out.println(prex);
        Set<String> keys = redisTemplate.keys(prex+"**");
        System.out.println("======keys:========");
        System.out.println(keys);
        if (CommonUtils.isNotNull(keys)) {
            redisTemplate.delete(keys);
        }
    }

    /**
     * 查看某个key是否存在
     * @param key
     * @return
     */
    public Boolean hasKey(String key, String childKey) {
        Set<String> keys = redisTemplate.keys(key + childKey);
        if(CommonUtils.isNotNull(keys)) {
            return true;
        }
        return false;
    }

    private String getFinallyKey(String key, String childKey) {
        return key + childKey;
    }
}